package com.lineage.server.templates;

import com.lineage.data.executor.QuestMobExecutor;
import com.lineage.data.quest.Chapter01R;
import com.lineage.data.quest.Chapter02R;
import com.lineage.server.datatables.NpcTable;
import com.lineage.server.datatables.QuesttSpawnTable;
import com.lineage.server.model.Instance.L1NpcInstance;
import com.lineage.server.model.Instance.L1PcInstance;
import com.lineage.server.model.L1Location;
import com.lineage.server.model.L1MobGroupSpawn;
import com.lineage.server.model.L1Teleport;
import com.lineage.server.model.map.L1Map;
import com.lineage.server.model.map.L1WorldMap;
import com.lineage.server.serverpackets.S_HelpMessage;
import com.lineage.server.serverpackets.ServerBasePacket;
import com.lineage.server.utils.L1SpawnUtil;
import com.lineage.server.utils.ListMapUtil;
import com.lineage.server.utils.PerformanceTimer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class L1QuestUser {
  private static final Log _log = LogFactory.getLog(L1QuestUser.class);
  
  private final int _id;
  
  private final int _questid;
  
  private final short _mapid;
  
  private QuestMobExecutor _mobNull;
  
  private boolean _info;
  
  private boolean _outStop;
  
  private int _time;
  
  private final ArrayList<L1PcInstance> _userList;
  
  private final ArrayList<L1NpcInstance> _npcList;
  
  private Random _random;
  
  private Chapter01R _hardin;
  
  private Chapter02R _orim;
  
  private int _score;
  
  private boolean _SpawnedDragon;
  
  public L1QuestUser(int id, int mapid, int questid) {
    this._mobNull = null;
    this._info = true;
    this._outStop = false;
    this._time = -1;
    this._random = new Random();
    this._SpawnedDragon = false;
    this._id = id;
    this._mapid = (short)mapid;
    this._questid = questid;
    this._userList = new ArrayList<>();
    this._npcList = new ArrayList<>();
  }
  
  public int get_id() {
    return this._id;
  }
  
  public int get_questid() {
    return this._questid;
  }
  
  public int get_mapid() {
    return this._mapid;
  }
  
  public void add(L1PcInstance pc) {
    try {
      if (!this._userList.contains(pc)) {
        this._userList.add(pc);
        pc.set_showId(this._id);
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } finally {
      _log.info("加入副本执行成员(" + this._questid + "-" + this._id + "):" + pc.getName());
    } 
  }
  
  public void remove(L1PcInstance pc) {
    try {
      if (this._userList.remove(pc))
        pc.set_showId(-1); 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } finally {
      _log.info("移出副本执行成员(" + this._questid + "-" + this._id + "):" + pc.getName());
    } 
  }
  
  public void set_time(int time) {
    this._time = time;
  }
  
  public int get_time() {
    return this._time;
  }
  
  public boolean is_time() {
    return (this._time != -1);
  }
  
  public ArrayList<L1PcInstance> pcList() {
    return this._userList;
  }
  
  public int size() {
    return this._userList.size();
  }
  
  public List<L1NpcInstance> npcList() {
    return this._npcList;
  }
  
  public void addNpc(L1NpcInstance npc) {
    this._npcList.add(npc);
  }
  
  public ArrayList<L1NpcInstance> npcList(int npcid) {
    ArrayList<L1NpcInstance> npcList = new ArrayList<>();
    Iterator<L1NpcInstance> iterator = this._npcList.iterator();
    while (iterator.hasNext()) {
      L1NpcInstance npc = iterator.next();
      if (npc.getNpcId() == npcid && !npc.isDead())
        npcList.add(npc); 
    } 
    if (npcList.size() <= 0)
      return null; 
    return npcList;
  }
  
  public int npcSize() {
    return this._npcList.size();
  }
  
  public int mobSize() {
    int i = 0;
    Iterator<L1NpcInstance> iterator = this._npcList.iterator();
    while (iterator.hasNext()) {
      L1NpcInstance npc = iterator.next();
      if (npc instanceof com.lineage.server.model.Instance.L1MonsterInstance)
        i++; 
    } 
    return i;
  }
  
  public void spawnQuestMob() {
    PerformanceTimer timer = new PerformanceTimer();
    try {
      ArrayList<L1QuestMobSpawn> spawnList = QuesttSpawnTable.get().getMobSpawn(this._questid);
      if (spawnList.size() > 0) {
        Iterator<L1QuestMobSpawn> iterator = spawnList.iterator();
        while (iterator.hasNext()) {
          L1QuestMobSpawn mobSpawn = iterator.next();
          if (mobSpawn.get_mapid() == this._mapid) {
            int count = mobSpawn.get_count();
            if (count <= 0)
              continue; 
            int i = 0;
            while (i < count) {
              spawn(mobSpawn);
              i++;
            } 
          } 
        } 
      } 
      spawnList.clear();
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } finally {
      _log.info("副本任务启动(" + this._questid + "-" + this._id + ") NPC完成召唤 数量:" + this._npcList.size() + 
          "(" + timer.get() + "ms)");
    } 
  }
  
  public void spawnQuestMob(int roundId) {
    try {
      ArrayList<L1QuestMobSpawn> spawnList = QuesttSpawnTable.get().getMobSpawn(this._questid);
      if (!spawnList.isEmpty()) {
        Iterator<L1QuestMobSpawn> iterator = spawnList.iterator();
        while (iterator.hasNext()) {
          L1QuestMobSpawn mobSpawn = iterator.next();
          if (mobSpawn.get_mapid() == this._mapid) {
            int count = (mobSpawn.get_count() <= 1) ? mobSpawn.get_count() : 
              this._random.nextInt(mobSpawn.get_count());
            if (count <= 0 || mobSpawn.get_round() != roundId)
              continue; 
            int i = 0;
            while (i < count) {
              spawn(mobSpawn);
              i++;
            } 
          } 
        } 
      } 
      spawnList.clear();
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public void spawnQuestMob(int roundId, int leastCount) {
    try {
      ArrayList<L1QuestMobSpawn> spawnList = QuesttSpawnTable.get().getMobSpawn(this._questid);
      if (!spawnList.isEmpty()) {
        int checkCount = 0;
        while (checkCount < leastCount) {
          Collections.shuffle(spawnList);
          Iterator<L1QuestMobSpawn> iterator = spawnList.iterator();
          while (iterator.hasNext()) {
            L1QuestMobSpawn mobSpawn = iterator.next();
            if (mobSpawn.get_mapid() == this._mapid) {
              int count = (mobSpawn.get_count() <= 1) ? mobSpawn.get_count() : 
                this._random.nextInt(mobSpawn.get_count());
              if (count <= 0 || mobSpawn.get_round() != roundId)
                continue; 
              checkCount += count;
              int i = 0;
              while (i < count) {
                spawn(mobSpawn);
                i++;
              } 
            } 
          } 
          checkCount++;
        } 
      } 
      spawnList.clear();
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public int spawnQuestMob(int roundId, int mobId1, int mobId2) {
    try {
      ArrayList<L1QuestMobSpawn> spawnList = QuesttSpawnTable.get().getMobSpawn(this._questid);
      if (!spawnList.isEmpty()) {
        Collections.shuffle(spawnList);
        Iterator<L1QuestMobSpawn> iterator = spawnList.iterator();
        while (iterator.hasNext()) {
          L1QuestMobSpawn mobSpawn = iterator.next();
          if (mobSpawn.get_mapid() == this._mapid && mobSpawn.get_npc_templateid() != mobId1 && 
            mobSpawn.get_npc_templateid() != mobId2 && mobSpawn.get_count() > 0 && 
            mobSpawn.get_round() == roundId)
            return mobSpawn.get_npc_templateid(); 
        } 
      } 
      spawnList.clear();
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
    return 0;
  }
  
  private void spawn(L1QuestMobSpawn mobSpawn) {
    try {
      int npcid = mobSpawn.get_npc_templateid();
      int group_id = mobSpawn.get_group_id();
      int locx1 = mobSpawn.get_locx1();
      int locy1 = mobSpawn.get_locy1();
      int locx2 = mobSpawn.get_locx2();
      int locy2 = mobSpawn.get_locy2();
      int heading = mobSpawn.get_heading();
      int mapid = mobSpawn.get_mapid();
      L1Npc template = NpcTable.get().getTemplate(npcid);
      if (template == null) {
        _log.error("召唤NPC编号: " + npcid + " 不存在资料库中!");
      } else if (locx1 != 0 && locy1 != 0 && locx2 != 0 && locy2 != 0) {
        int x = 0;
        int y = 0;
        L1Map map = L1WorldMap.get().getMap((short)mapid);
        int tryCount = 0;
        while (tryCount <= 50) {
          x = this._random.nextInt(locx2 - locx1) + locx1;
          y = this._random.nextInt(locy2 - locy1) + locy1;
          if (map.isInMap(x, y) && map.isPassable(x, y, null)) {
            L1Location loc = new L1Location(x, y, mapid);
            L1NpcInstance mob = L1SpawnUtil.spawn(npcid, loc, heading, this._id);
            this._npcList.add(mob);
            groupSpawn(group_id, mob);
            break;
          } 
          tryCount++;
        } 
      } else {
        L1Location loc2 = new L1Location(locx1, locy1, mapid);
        L1NpcInstance mob2 = L1SpawnUtil.spawn(npcid, loc2, heading, this._id);
        this._npcList.add(mob2);
        groupSpawn(group_id, mob2);
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  private void groupSpawn(int group_id, L1NpcInstance mob) {
    if (group_id != 0)
      L1MobGroupSpawn.getInstance().doSpawn(mob, group_id, true, true); 
    if (mob.getMobGroupInfo() != null) {
      Iterator<L1NpcInstance> iterator = mob.getMobGroupInfo().getList().iterator();
      while (iterator.hasNext()) {
        L1NpcInstance mobx = iterator.next();
        if (!mobx.equals(mob))
          this._npcList.add(mobx); 
      } 
    } 
  }
  
  public void removeMob(L1NpcInstance mob) {
    try {
      if (this._npcList.remove(mob) && is_info())
        sendPackets((ServerBasePacket)new S_HelpMessage("\\fY剩余怪物：" + mobSize())); 
      if (mobSize() <= 0 && this._mobNull != null)
        this._mobNull.stopQuest(this); 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public void removeMob() {
    try {
      ArrayList<L1NpcInstance> allList = new ArrayList<>();
      allList.addAll(this._npcList);
      Iterator<L1NpcInstance> iterator = allList.iterator();
      while (iterator.hasNext()) {
        L1NpcInstance npc = iterator.next();
        npc.deleteMe();
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } finally {
      ListMapUtil.clear(this._npcList);
      _log.info("副本任务结束(" + this._questid + "-" + this._id + ")");
    } 
  }
  
  public void endQuest() {
    try {
      Iterator<L1PcInstance> iterator = this._userList.iterator();
      while (iterator.hasNext()) {
        L1PcInstance pc = iterator.next();
        if (pc.getMapId() == this._mapid)
          L1Teleport.teleport(pc, 33430, 32814, (short)4, 4, true); 
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } finally {
      ListMapUtil.clear(this._userList);
    } 
  }
  
  public void sendPackets(ServerBasePacket basePacket) {
    try {
      Iterator<L1PcInstance> iterator = this._userList.iterator();
      while (iterator.hasNext()) {
        L1PcInstance pc = iterator.next();
        pc.sendPackets(basePacket);
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public void set_info(boolean _info) {
    this._info = _info;
  }
  
  public boolean is_info() {
    return this._info;
  }
  
  public void set_outStop(boolean _outStop) {
    this._outStop = _outStop;
  }
  
  public boolean is_outStop() {
    return this._outStop;
  }
  
  public void set_object(QuestMobExecutor mobNull) {
    this._mobNull = mobNull;
  }
  
  public QuestMobExecutor get_object() {
    return this._mobNull;
  }
  
  public void set_hardinR(Chapter01R hardin) {
    this._hardin = hardin;
  }
  
  public Chapter01R get_hardinR() {
    return this._hardin;
  }
  
  public void set_orimR(Chapter02R orim) {
    this._orim = orim;
  }
  
  public Chapter02R get_orimR() {
    return this._orim;
  }
  
  public void add_score(int i) {
    this._score += i;
  }
  
  public int get_score() {
    return this._score;
  }
  
  public boolean is_SpawnedDragon() {
    return this._SpawnedDragon;
  }
  
  public void set_SpawnedDragon(boolean _SpawnedDragon) {
    this._SpawnedDragon = _SpawnedDragon;
  }
}
